package com.fy.fyspace.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fy.fyspace.mapper.HotnessRankingCacheMapper;
import com.fy.fyspace.mapper.PictureHotnessMapper;
import com.fy.fyspace.mapper.PictureMapper;
import com.fy.fyspace.model.entity.HotnessRankingCache;
import com.fy.fyspace.model.entity.Picture;
import com.fy.fyspace.model.entity.PictureHotness;
import com.fy.fyspace.model.vo.hotness.HotnessRankingVO;
import com.fy.fyspace.service.HotnessRankingCacheService;
import com.fy.fyspace.service.PictureHotnessService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 热度排行榜缓存Service实现类
 * 设计模式：服务层实现模式
 * 作用：实现热度排行榜缓存相关的业务逻辑，支持Redis缓存
 */
@Slf4j
@Service
public class HotnessRankingCacheServiceImpl implements HotnessRankingCacheService {
    
    @Autowired
    private HotnessRankingCacheMapper rankingCacheMapper;
    
    @Autowired
    private PictureHotnessMapper pictureHotnessMapper;
    
    @Autowired
    private PictureHotnessService pictureHotnessService;
    
    @Autowired
    private PictureMapper pictureMapper;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    // Redis缓存键前缀
    private static final String RANKING_CACHE_KEY_PREFIX = "hotness:ranking:";
    private static final String RANKING_CACHE_EXPIRE_TIME = "hotness:ranking:expire";
    
    // 缓存过期时间（24小时）
    private static final long CACHE_EXPIRE_HOURS = 24;
    
    @Override
    @Transactional
    public boolean updateRankingCache(PictureHotness pictureHotness) {
        try {
            log.debug("更新排行榜缓存，图片ID: {}", pictureHotness.getPictureId());
            
            // 查询图片信息
            Picture picture = pictureMapper.selectById(pictureHotness.getPictureId());
            if (picture == null) {
                log.warn("图片不存在，无法更新排行榜缓存，图片ID: {}", pictureHotness.getPictureId());
                return false;
            }
            
            // 更新当前热度排行
            updateRankingByType(picture, pictureHotness, "CURRENT", pictureHotness.getCurrentScore());
            
            // 更新昨日热度排行
            if (pictureHotness.getYesterdayScore() != null) {
                updateRankingByType(picture, pictureHotness, "YESTERDAY", pictureHotness.getYesterdayScore());
            }
            
            // 更新上周热度排行
            if (pictureHotness.getLastWeekScore() != null) {
                updateRankingByType(picture, pictureHotness, "LAST_WEEK", pictureHotness.getLastWeekScore());
            }
            
            // 更新上月热度排行
            if (pictureHotness.getLastMonthScore() != null) {
                updateRankingByType(picture, pictureHotness, "LAST_MONTH", pictureHotness.getLastMonthScore());
            }
            
            // 清除Redis缓存，强制重新加载
            clearRedisCache();
            
            return true;
            
        } catch (Exception e) {
            log.error("更新排行榜缓存失败，图片ID: {}", pictureHotness.getPictureId(), e);
            return false;
        }
    }
    
    @Override
    @Transactional
    public int batchUpdateRankingCache(List<PictureHotness> pictureHotnessList) {
        if (pictureHotnessList.isEmpty()) {
            return 0;
        }
        
        log.info("批量更新排行榜缓存，数量: {}", pictureHotnessList.size());
        
        int successCount = 0;
        for (PictureHotness hotness : pictureHotnessList) {
            if (updateRankingCache(hotness)) {
                successCount++;
            }
        }
        
        // 清除Redis缓存，强制重新加载
        clearRedisCache();
        
        log.info("批量更新排行榜缓存完成，成功数量: {}/{}", successCount, pictureHotnessList.size());
        return successCount;
    }
    
    @Override
    @Transactional
    public boolean regenerateRankingCache(String rankType) {
        try {
            log.info("重新生成排行榜缓存，类型: {}", rankType);
            
            // 清除现有缓存
            clearRankingCache(rankType);
            
            // 查询所有热度数据
            List<PictureHotness> allHotness = getAllHotnessData();
            
            if (allHotness.isEmpty()) {
                log.warn("没有热度数据，无法生成排行榜缓存");
                return false;
            }
            
            // 根据排行类型排序
            List<PictureHotness> sortedList = sortByRankType(allHotness, rankType);
            
            // 生成排行榜缓存
            List<HotnessRankingCache> cacheList = new ArrayList<>();
            for (int i = 0; i < Math.min(sortedList.size(), 100); i++) { // 只缓存前100名
                PictureHotness hotness = sortedList.get(i);
                Picture picture = pictureMapper.selectById(hotness.getPictureId());
                
                if (picture != null) {
                    HotnessRankingCache cache = createRankingCache(picture, hotness, rankType, i + 1);
                    cacheList.add(cache);
                }
            }
            
            // 批量保存缓存到数据库
            if (!cacheList.isEmpty()) {
                rankingCacheMapper.batchInsertOrUpdate(cacheList);
            }
            
            // 更新Redis缓存
            updateRedisCache(rankType, cacheList);
            
            log.info("排行榜缓存重新生成完成，类型: {}, 数量: {}", rankType, cacheList.size());
            return true;
            
        } catch (Exception e) {
            log.error("重新生成排行榜缓存失败，类型: {}", rankType, e);
            return false;
        }
    }
    
    @Override
    public List<HotnessRankingVO> getRankingList(String rankType, Integer limit) {
        try {
            log.debug("获取排行榜数据，类型: {}, 数量: {}", rankType, limit);
            
            // 先从Redis缓存获取
            List<HotnessRankingVO> redisResult = getRankingFromRedis(rankType, limit);
            if (redisResult != null && !redisResult.isEmpty()) {
                log.debug("从Redis缓存获取排行榜数据，类型: {}", rankType);
                return redisResult;
            }
            
            // Redis缓存不存在，从数据库获取
            List<HotnessRankingCache> cacheList = rankingCacheMapper.selectByRankType(rankType, limit);
            
            // 转换为VO
            List<HotnessRankingVO> voList = cacheList.stream()
                    .map(this::convertToVO)
                    .collect(Collectors.toList());
            
            // 更新Redis缓存
            if (!voList.isEmpty()) {
                updateRedisCache(rankType, cacheList);
            }
            
            return voList;
            
        } catch (Exception e) {
            log.error("获取排行榜数据失败，类型: {}", rankType, e);
            return new ArrayList<>();
        }
    }
    
    @Override
    public List<HotnessRankingCache> getRankingCache(String rankType, Integer limit) {
        try {
            return rankingCacheMapper.selectByRankType(rankType, limit);
        } catch (Exception e) {
            log.error("获取排行榜缓存失败，类型: {}", rankType, e);
            return new ArrayList<>();
        }
    }
    
    @Override
    @Transactional
    public boolean clearRankingCache(String rankType) {
        try {
            log.info("清除排行榜缓存，类型: {}", rankType);
            
            // 清除数据库缓存
            int result = rankingCacheMapper.deleteByRankType(rankType);
            log.info("数据库排行榜缓存清除完成，类型: {}, 影响行数: {}", rankType, result);
            
            // 清除Redis缓存
            clearRedisCacheByType(rankType);
            
            return true;
        } catch (Exception e) {
            log.error("清除排行榜缓存失败，类型: {}", rankType, e);
            return false;
        }
    }
    
    @Override
    @Transactional
    public boolean clearAllRankingCache() {
        try {
            log.info("清除所有排行榜缓存");
            
            // 清除所有类型的缓存
            clearRankingCache("CURRENT");
            clearRankingCache("YESTERDAY");
            clearRankingCache("LAST_WEEK");
            clearRankingCache("LAST_MONTH");
            
            // 清除所有Redis缓存
            clearRedisCache();
            
            log.info("所有排行榜缓存清除完成");
            return true;
        } catch (Exception e) {
            log.error("清除所有排行榜缓存失败", e);
            return false;
        }
    }
    
    /**
     * 从Redis获取排行榜数据
     */
    @SuppressWarnings("unchecked")
    private List<HotnessRankingVO> getRankingFromRedis(String rankType, Integer limit) {
        try {
            String cacheKey = RANKING_CACHE_KEY_PREFIX + rankType;
            Object cachedData = redisTemplate.opsForValue().get(cacheKey);
            
            if (cachedData != null) {
                List<HotnessRankingVO> voList = (List<HotnessRankingVO>) cachedData;
                return voList.stream()
                        .limit(limit)
                        .collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.warn("从Redis获取排行榜数据失败，类型: {}", rankType, e);
        }
        return null;
    }
    
    /**
     * 更新Redis缓存
     */
    private void updateRedisCache(String rankType, List<HotnessRankingCache> cacheList) {
        try {
            String cacheKey = RANKING_CACHE_KEY_PREFIX + rankType;
            
            // 转换为VO列表
            List<HotnessRankingVO> voList = cacheList.stream()
                    .map(this::convertToVO)
                    .collect(Collectors.toList());
            
            // 存储到Redis，设置过期时间
            redisTemplate.opsForValue().set(cacheKey, voList, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
            
            log.debug("Redis缓存更新成功，类型: {}, 数量: {}", rankType, voList.size());
            
        } catch (Exception e) {
            log.warn("更新Redis缓存失败，类型: {}", rankType, e);
        }
    }
    
    /**
     * 清除指定类型的Redis缓存
     */
    private void clearRedisCacheByType(String rankType) {
        try {
            String cacheKey = RANKING_CACHE_KEY_PREFIX + rankType;
            redisTemplate.delete(cacheKey);
            log.debug("Redis缓存清除成功，类型: {}", rankType);
        } catch (Exception e) {
            log.warn("清除Redis缓存失败，类型: {}", rankType, e);
        }
    }
    
    /**
     * 清除所有Redis缓存
     */
    private void clearRedisCache() {
        try {
            String pattern = RANKING_CACHE_KEY_PREFIX + "*";
            redisTemplate.delete(redisTemplate.keys(pattern));
            log.debug("所有Redis缓存清除成功");
        } catch (Exception e) {
            log.warn("清除所有Redis缓存失败", e);
        }
    }
    
    /**
     * 根据排行类型更新排行榜
     */
    private void updateRankingByType(Picture picture, PictureHotness hotness, String rankType, java.math.BigDecimal score) {
        // 查询现有缓存
        LambdaQueryWrapper<HotnessRankingCache> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HotnessRankingCache::getPictureId, picture.getId())
               .eq(HotnessRankingCache::getRankType, rankType);
        
        HotnessRankingCache existingCache = rankingCacheMapper.selectOne(wrapper);
        
        if (existingCache != null) {
            // 更新现有缓存
            existingCache.setCurrentScore(score);
            rankingCacheMapper.updateById(existingCache);
        } else {
            // 创建新缓存
            HotnessRankingCache newCache = createRankingCache(picture, hotness, rankType, 0);
            rankingCacheMapper.insert(newCache);
        }
    }
    
    /**
     * 创建排行榜缓存对象
     */
    private HotnessRankingCache createRankingCache(Picture picture, PictureHotness hotness, String rankType, int rankPosition) {
        HotnessRankingCache cache = new HotnessRankingCache();
        cache.setPictureId(picture.getId());
        cache.setPictureName(picture.getName());
        cache.setPictureUrl(picture.getUrl());
        cache.setThumbnailUrl(picture.getThumbnailUrl());
        cache.setCurrentScore(hotness.getCurrentScore());
        cache.setYesterdayScore(hotness.getYesterdayScore());
        cache.setLastWeekScore(hotness.getLastWeekScore());
        cache.setLastMonthScore(hotness.getLastMonthScore());
        cache.setRankType(rankType);
        cache.setRankPosition(rankPosition);
        return cache;
    }
    
    /**
     * 获取所有热度数据
     */
    private List<PictureHotness> getAllHotnessData() {
        try {
            // 查询所有热度数据，限制数量避免内存溢出
            List<PictureHotness> hotnessList = pictureHotnessMapper.selectAllWithLimit(1000);
            
            log.debug("获取热度数据成功，数量: {}", hotnessList.size());
            return hotnessList;
            
        } catch (Exception e) {
            log.error("获取热度数据失败", e);
            return new ArrayList<>();
        }
    }
    
    /**
     * 根据排行类型排序
     */
    private List<PictureHotness> sortByRankType(List<PictureHotness> hotnessList, String rankType) {
        return hotnessList.stream()
                .sorted((h1, h2) -> {
                    java.math.BigDecimal score1 = getScoreByRankType(h1, rankType);
                    java.math.BigDecimal score2 = getScoreByRankType(h2, rankType);
                    return score2.compareTo(score1); // 降序排列
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 根据排行类型获取分数
     */
    private java.math.BigDecimal getScoreByRankType(PictureHotness hotness, String rankType) {
        switch (rankType) {
            case "CURRENT":
                return hotness.getCurrentScore() != null ? hotness.getCurrentScore() : java.math.BigDecimal.ZERO;
            case "YESTERDAY":
                return hotness.getYesterdayScore() != null ? hotness.getYesterdayScore() : java.math.BigDecimal.ZERO;
            case "LAST_WEEK":
                return hotness.getLastWeekScore() != null ? hotness.getLastWeekScore() : java.math.BigDecimal.ZERO;
            case "LAST_MONTH":
                return hotness.getLastMonthScore() != null ? hotness.getLastMonthScore() : java.math.BigDecimal.ZERO;
            default:
                return java.math.BigDecimal.ZERO;
        }
    }
    
    /**
     * 转换为VO对象
     */
    private HotnessRankingVO convertToVO(HotnessRankingCache cache) {
        HotnessRankingVO vo = new HotnessRankingVO();
        BeanUtils.copyProperties(cache, vo);
        return vo;
    }
} 